import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class DebugLogAnalysis {

    // 背书节点日志标记
    String flagEndorserPre = "背书阶段 preProcess()";
    String flagEndorserTxSimulator = "背书阶段 simulateProposalStart()";
    String flagEndorserSign1 = "背书阶段 endorseProposal()";
    String flagEndorserAll = "背书阶段总时间";

    String flagEndorserTxSimulatorCheckCCInfo = "背书模拟阶段 检查链码信息耗时";
    String flagEndorserTxSimulatorCallCC = "背书模拟阶段 链码执行耗时";
    String flagEndorserTxSimulatorProcessResult = "背书模拟阶段 模拟结果处理耗时";

    // 提交节点日志标记
    String flagCommiterPrepare = "记账阶段 preCommit()";
    String flagCommiterCommitWithDetail = "[txchannel] Committed block";
    String flagCommiterCommit = "记账阶段 commitWithPvtData()";

    // 排序节点日志标记
    String flagOrdererEnqueueStart = "Enqueuing message into batch";
    String flagOrdererEnqueueEnd = "Broadcast has successfully enqueued message";
    String flagOrdererCreatedBlock = "Proposed block";
    String flagOrdererWroteBlock = "Wrote block";

    String logFilePath = "/home/cy/Documents/ATL/docs/开发工作/Fabric性能实验/logs/debugErrorLog/debug_batch3.log";
    String outputFilePath = "/home/cy/Documents/ATL/docs/开发工作/Fabric性能实验/logs/debugErrorLog/debug_batch3_output.log";

    public static void main(String[] args) {
        new DebugLogAnalysis().loadLogFile();
    }

    public void loadLogFile() {
        try {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(logFilePath)));
            BufferedReader in = new BufferedReader(new InputStreamReader(bis, "utf-8"), 10 * 1024 * 1024);
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(outputFilePath)));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(bos, "utf-8"), 1024);
            String strTime = null;
            String[] subStrTime = null;
            String line = null;

            float totalTimeEndorserPreProcess = 0F;
            float totalTimeEndorserTxSimulate = 0F;
            float totalTimeEndorserSign = 0F;
            float totalTimeEndorseAll = 0F;

            float totalTimeEndorserTxSimulatorCheckCCInfo = 0F;
            float totalTimEndorserTxSimulatorCallCC = 0F;
            float totalTimEndorserTxSimulatorProcessResult = 0F;

            float totalTimeCommiterPrepare = 0F;
            float totalTimeCommiterStateValidation = 0F;
            float totalTimeCommiterBlockAndPvtdataCommit = 0F;
            float totalTimeCommiterStateCommit = 0F;
            float totalTimeCommiterCommit = 0F;

            float totalTx = 0F;
            float totalTimeOrder = 0F;

            long endorseCount = 0;
            long commitCount = 0;

            while (in.ready()) {
                line = in.readLine();

                if (line.contains(flagEndorserPre)) {
                    totalTimeEndorserPreProcess += getMillisecond(line);
                    endorseCount++;
                } else if (line.contains(flagEndorserTxSimulator)) {
                    totalTimeEndorserTxSimulate += getMillisecond(line);
                } else if (line.contains(flagEndorserTxSimulatorCheckCCInfo)) {
                    totalTimeEndorserTxSimulatorCheckCCInfo += getMillisecond(line);
                } else if (line.contains(flagEndorserTxSimulatorCallCC)) {
                    totalTimEndorserTxSimulatorCallCC += getMillisecond(line);
                } else if (line.contains(flagEndorserTxSimulatorProcessResult)) {
                    totalTimEndorserTxSimulatorProcessResult += getMillisecond(line);
                } else if (line.contains(flagEndorserSign1)) {
                    totalTimeEndorserSign += getMillisecond(line);
                } else if (line.contains(flagEndorserAll)) {
                    totalTimeEndorseAll += getMillisecond(line);
                } else if (line.contains(flagCommiterPrepare)) {
                    totalTimeCommiterPrepare += getMillisecond(line);
                } else if (line.contains(flagCommiterCommitWithDetail)) {
                    List<Long> threeTimes = getThreeTimes(line);
                    totalTimeCommiterStateValidation += threeTimes.get(0);
                    totalTimeCommiterBlockAndPvtdataCommit += threeTimes.get(1);
                    totalTimeCommiterStateCommit += threeTimes.get(2);
                } else if (line.contains(flagCommiterCommit)) {
                    commitCount++;
                    totalTimeCommiterCommit += getMillisecond(line);
                }
            }

            out.write("                        各阶段平均时间（ms）： \r\n");
            out.write("                                 总背书次数：" + endorseCount + "\r\n");
            out.write("           背书阶段 preProcess() 平均验证耗时：" + (totalTimeEndorserPreProcess / endorseCount) + "\r\n");
            out.write("背书阶段 simulateProposalStart() 模拟平均耗时：" + (totalTimeEndorserTxSimulate / endorseCount) + "\r\n");
            out.write("              背书模拟阶段 检查链码信息平均耗时：    -" + (totalTimeEndorserTxSimulatorCheckCCInfo / endorseCount) + "\r\n");
            out.write("                     背书模拟阶段 链码执行耗时：   -" + (totalTimEndorserTxSimulatorCallCC / endorseCount) + "\r\n");
            out.write("                 背书模拟阶段 模拟结果处理耗时：    -" + (totalTimEndorserTxSimulatorProcessResult / endorseCount) + "\r\n");
            out.write("   背书阶段 endorseProposal() 签名背书平均耗时：" + (totalTimeEndorserSign / endorseCount) + "\r\n");
            out.write("                           背书阶段总平均耗时：" + (totalTimeEndorseAll / endorseCount) + "\r\n");
            out.newLine();
            out.write("                              总提交区块次数：" + commitCount + "\r\n");
            out.write("               记账阶段 preCommit() 平均耗时：" + (totalTimeCommiterPrepare / commitCount) + "\r\n");
            out.write("                     记账阶段 状态验证平均耗时：" + (totalTimeCommiterStateValidation / commitCount) + "\r\n");
            out.write("             记账阶段 提交区块和私有数据平均耗时：" + (totalTimeCommiterBlockAndPvtdataCommit / commitCount) + "\r\n");
            out.write("                     记账阶段 提交状态平均耗时：" + (totalTimeCommiterStateCommit / commitCount) + "\r\n");
            out.write("                          记账阶段 总平均耗时：" + (totalTimeCommiterCommit / commitCount) + "\r\n");

            bos.flush();
            out.flush();
            in.close();
            bis.close();
            out.close();
            bos.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private List<Long> getThreeTimes(String line) {
//        2020-04-01 14:32:29.849 CST [kvledger] CommitWithPvtData -> ERRO 032 [txchannel] Committed block [4] with 1 transaction(s) in 284ms (state_validation=13ms block_and_pvtdata_commit=195ms state_commit=36ms) commitHash=
        List<Long> list = new ArrayList<Long>();
        String substring = line.substring(line.lastIndexOf("(") + 1, line.lastIndexOf(")"));
        String[] strings = substring.split(" ");
        for (String string : strings) {
            String substring1 = string.substring(string.lastIndexOf("=") + 1, string.length() - 2);
            list.add(Long.parseLong(substring1));
        }

        return list;
    }

    public Float getMillisecond(String line) {
        int i = line.lastIndexOf(" ");
        String substring = line.substring(i + 1, line.length() - 2);
        float v = Float.parseFloat(substring);
        if (line.substring(line.length() - 2).equals("μs")) {
            v /= 1000.0F;
        }
        return v;
    }
}
